/**
 * @author Radhika Karandikar
 * @date - 02/21/2009
 * @course - 15637
 * 
 * This is an abstract class for different types of actions.
 */

package edu.cmu.vlis.wassup.db;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;

import org.mybeans.dao.*;
import org.mybeans.factory.*;

import edu.cmu.vlis.wassup.databean.User;

/**
 * The class for access User table in database
 * @author Jassica
 *
 */
public class UserDAO {
	private BeanFactory<User> factory;
	
	private static void loadProperties(){
        Properties props = new Properties();
        try {
            props.load(new FileInputStream("src/properties"));
            System.getProperties().putAll(props);
            
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

	public UserDAO() throws DAOException {
		try {
			// Set up the jdbc driver
			BeanTable.useJDBC("com.mysql.jdbc.Driver", System.getProperty("org.mybeans.factory.jdbcURL")+
					"?user="+System.getProperty("org.mybeans.factory.user")
					+"&password="+System.getProperty("org.mybeans.factory.password"));
			//System.out.println("Hello "+System.getProperty("org.mybeans.factory.user"));
			
			// initialize table and bean factory
			BeanTable<User> userTable = BeanTable.getInstance(User.class,"User");
			if (!userTable.exists())
				userTable.create("userName");
			
			// Long running web apps need to clean up idle database connections.
	        // So we can tell each BeanTable to clean them up.  (You would only notice
	        // a problem after leaving your web app running for several hours.)
	        userTable.setIdleConnectionCleanup(true);
	        
	        factory = userTable.getFactory();
		} catch (BeanFactoryException e) {
			throw new DAOException(e);
		}
	}
	
	/**
	 * To check whether the given user already exists
	 * @param e_mail indicates various users
	 * @return boolean result  
	 */
	public boolean isUserExist(String userName) {
		
		User user = null;
		boolean result = false;
		try {
			user = factory.lookup(userName);
			if (user != null) {
				result = true;
			}
		} catch (RollbackException e) {
			System.out.println("inside isUserExist");
		}
		return result;
	}
	
	public void create(User user) throws DAOException {
        try {
        	synchronized (factory) {
			   	Transaction.begin();
			   	User dbUser = factory.create(user.getUserName());
			   	factory.copyInto(user,dbUser);
			   	Transaction.commit();
			   	System.out.println("User created successfully " + user);
        	}
		} catch (DuplicateKeyException e) {
			throw new DAOException("A user with username " + user.getUserName() + " already exists");
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	public User lookup(String userName) throws DAOException {
		try {
			return factory.lookup(userName);
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	
	public User[] getUsers() throws DAOException {
		try {
			User[] users = factory.match();
			// We want them sorted by last and first names (as per User.compareTo());
			Arrays.sort(users);  
			return users;
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	public void setPassword(String userName, String password) throws DAOException {
        try {
        	Transaction.begin();
			User dbUser = factory.lookup(userName);
			
			if (dbUser == null) {
				throw new DAOException("User "+userName+" no longer exists");
			}
			
			dbUser.setPassword(password);
//			dbUser.setSalt(dbUser.getSalt());
//			dbUser.setHashedPassword(dbUser.getHashedPassword());
			
			Transaction.commit();
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	public void activate(String userName) throws DAOException {
		try {
        	Transaction.begin();
			User dbUser = factory.lookup(userName);
			
			if (dbUser == null) {
				throw new DAOException("User "+userName+" no longer exists");
			}
			
			dbUser.setActivated(true);
			Transaction.commit();
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
		
	}
	
	/**
	 *  Update an profile record in the table
	 *  Insert new tuple in the profile table if the record does not exist
	 *  Update the new tuple information 
	 * @param user_id
	 * @param p
	 * @return
	 * @throws RollbackException
	 */
	public User update(String e_mail, User p) throws DAOException {
		User dbUser = null;
		try {
        	Transaction.begin();
			dbUser = factory.lookup(e_mail);
			
			if (dbUser == null) {
				throw new DAOException("User "+e_mail+" no longer exists");
			}
			factory.copyInto(p, dbUser);
			
			Transaction.commit();
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
		return dbUser;
	}


	/**
	 * Get all users living in one specific city
	 * @param city
	 * @return
	 * @throws RollbackException
	 * @throws DAOException 
	 */
	public User[] getLocationUsers(String city) throws DAOException {
		User[] users = null;
		try {
			users = factory.match(MatchArg.equalsIgnoreCase("city",city));
		}
		catch (RollbackException e) {
			throw new DAOException(e);
		}
		return users;
	}


	/**
	 * Get a user from the input first name and last name
	 * @param name
	 * @return
	 * @throws DAOException 
	 */
	public User getUserFromName(String firstName, String lastName) throws DAOException {
		User user = null;
		try {
			User[] users = factory.match(MatchArg.equalsIgnoreCase("firstName",firstName), 
					MatchArg.equalsIgnoreCase("lastName", lastName));
			if (users.length == 1) 
				user = users[0];
			else {
				throw new DAOException("There are multiple users with the same name or none!");
			}
		}
		catch (RollbackException e) {
			throw new DAOException(e);
		}
		return user;
	}

	public BeanFactory<User> getFactory() {
		return factory;
	}
	
	public static void main(String[] args) {
		loadProperties();
		
//		String userName = "radh@cmu.edu";
		
		try {
			UserDAO userDAO = new UserDAO();
			User user = userDAO.createUser();
			userDAO.create(user);
			System.out.println("User created successfully " + user);
//			userDAO.setPassword(userName, "radhika");
			user = userDAO.lookup("upcoming");
			boolean result = user.isPasswordMatch("1234");
			if(result)
				System.out.println("match");
			else
				System.out.println("NOPE");
			System.out.println("The salt is "+user.getSalt());
			System.out.println("The salt is "+user.getHashedPassword());
			
			userDAO.setPassword("upcoming", "1234");
			user = userDAO.lookup("upcoming");
			System.out.println("The salt is "+user.getSalt());
			System.out.println("The salt is "+user.getHashedPassword());
			result = user.isPasswordMatch("1234");
			if(result)
				System.out.println("match");
			else
				System.out.println("NOPE");
			
//			userDAO.activate(userName);
//			System.out.println(userDAO.lookup(userName));
//			
//			result = userDAO.isUserExist(userName);
//			if(result)
//				System.out.println("failure");
//			else
//				System.out.println("success");
//			
//			
			System.exit(0);
		} 
		catch (DAOException e) {
			System.out.println("User Insert exception");
			e.printStackTrace();
		}
	}
	
	private User createUser() {
		User user = new User("upcoming");
		
		user.setFirstName("Yahoo");
		user.setLastName("Yahoo");
		
		user.setPassword("happy?");
				
		return user;
	}
}
